package io.xdag;

import java.io.File;
import java.io.IOException;
import java.util.Optional;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.sanityinc.jargs.CmdLineParser;
import com.sanityinc.jargs.CmdLineParser.Option;

import io.xdag.conf.Configuration;
import io.xdag.conf.Configuration.DefaultConfSettings;

public class XDAG 
{
	public static final String MAINNET_NAME = "XDAG";
    public static final String TESTNET_NAME = "XDAG Testnet";
	public static final String VERSION = "0.0.1";
	
    public static void main( String[] args ) throws Exception{
    	configureLogging();
    	XDAGLauncher.main(args);
    }
    
    
    private static void configureLogging() {
        String config = System.getProperty("logback.configurationFile");
        String level = System.getProperty("logging-level", "").toUpperCase();
        switch (level) {
            case "OFF":
            case "ERROR":
            case "WARN":
            case "INFO":
            case "DEBUG":
            case "TRACE":
                break;
            case "ALL":
                level = "TRACE";
                break;
            default:
                level = "INFO";
        }
        System.getProperties().put("logging-level", level);
        System.out.println("Logging - property 'logging-level' set to: [" + level + "]");
        if (config != null) {
            System.out.println("Logging - alternate logging configuration file specified at: '" + config + "'");
        }
    }
    
    private static class XDAGLauncher {
        private static final Logger log = LoggerFactory.getLogger(XDAGLauncher.class);

        public static Configuration configuration;

//        private static final String TESTNET_FLAG_REQUIRED = "--testnet flag must be turned on to use ";

        public static void main(final String[] args) throws Exception {

        	//初始化配置
            configuration = new Configuration();
            //校验配置
            if (!isValidated(configuration, args)) {
                printUsage();
                return;
            }

            log.info("Welcome to {} {}", configuration.booling(DefaultConfSettings.TESTNET) ? TESTNET_NAME : MAINNET_NAME, VERSION);
            shutdownHook();

            if (configuration.booling(DefaultConfSettings.DEBUG)) {
                log.info("You have set the debug flag. To enable debug output, you need to uncomment the DEBUG appender in the source tree at xdag/src/main/resources/logback.xml and re-package XDAG.jar");
            }

            if (configuration.booling(DefaultConfSettings.EXPORT)) {
                File exportDir = new File("export");
                if (!exportDir.exists()) {
                    log.info("Create directory 'export'");
                    try {
                        exportDir.mkdir();
                    } catch (SecurityException e) {
                        log.error("Could not create directory", e);
                    }
                }
                exportDir = new File("export-solid");
                if (!exportDir.exists()) {
                    log.info("Create directory 'export-solid'");
                    try {
                        exportDir.mkdir();
                    } catch (SecurityException e) {
                        log.error("Could not create directory", e);
                    }
                }
            }

            try {
            	//初始化加密组建
            	//初始化网络
            	//初始化钱包
            	//初始化block
            	//初始化矿池
            	
                log.info("XDAG Node initialised correctly.");
            } catch (Exception e) {
                log.error("Exception during XDag node initialisation: ", e);
                throw e;
            }
        }

        private static boolean isValidated(final Configuration configuration, final String[] args) throws IOException {

            boolean configurationInit = configuration.init();

            if (args == null || (args.length < 1 && !configurationInit)) {
                log.error("Invalid arguments list. Provide ini-file 'xdag.ini' or API port number (i.e. '-p 7677').");
                return false;
            }

            final CmdLineParser parser = new CmdLineParser();

            final Option<String> config = parser.addStringOption('c', "config");
            final Option<String> publicAddress = parser.addStringOption('p',"public-address");
            final Option<Boolean> testnet = parser.addBooleanOption('t',"testnet");
            final Option<Boolean> help = parser.addBooleanOption('h', "help");
            final Option<Boolean> daemon = parser.addBooleanOption('d', "daemon");
            final Option<Integer> miningThreads = parser.addIntegerOption("m");

            try {
                parser.parse(args);
            } catch (CmdLineParser.OptionException e) {
                log.error("CLI error: ", e);
                throw new IllegalArgumentException("CLI error: " + e, e);
            }

            // optional config file path
            String confFilePath = parser.getOptionValue(config);
            if (confFilePath != null) {
                configuration.put(DefaultConfSettings.CONFIG, confFilePath);
                configuration.init();
            }

            //This block cannot be moved down
            final boolean isTestnet = Optional.ofNullable(parser.getOptionValue(testnet)).orElse(Boolean.FALSE)
                || configuration.booling(DefaultConfSettings.TESTNET);
            if (isTestnet) {
                configuration.put(DefaultConfSettings.TESTNET, "true");
            }

            // mandatory args
            String iniaddress = configuration.getIniValue(DefaultConfSettings.PUBLIC_ADDRESS.name());
            final String cpublicAddress = iniaddress == null ? parser.getOptionValue(publicAddress) : iniaddress;
            if (cpublicAddress == null) {
                log.error("Invalid arguments list. Provide at least the PORT in xdag.ini or with -p option");
                return false;
            } else {
                configuration.put(DefaultConfSettings.PUBLIC_ADDRESS, cpublicAddress);
            }

            // optional flags
            if (parser.getOptionValue(help) != null) {
                return false;
            }

         
            return true;
        }

        private static void printUsage() {
            log.info("Usage: java -jar {}-{}.jar " +
                    "[{-a <address> } 'specify your address to use in the miner'] " +
                    "[{-c --config }  'using default configuration'] " +
                    "[{-d --daemon} 'run as daemon (default is interactive mode)'] " +
                    "[{-h --help} 'print this help'] " +
                    "[{-i} 'run as interactive terminal for daemon running in this folder'] " +
                    "[{-l} 'output non zero balances of all accounts'] " +
                    "[{-m <N> } 'use N CPU mining threads (default is 0)']" +
                    "[{-p <ip:port> } 'public address of this node']" +
                    "[{-p <ip:port:CFG> } 'run the pool, bind to ip:port, CFG is miners:maxip:maxconn:fee:reward:direct:fund']" +
                    "[{-r} 'load local blocks and wait for 'run' command to continue']" +
                    "[{-s <ip:port> } 'address of this node to bind to']" +
                    "[{-t --testnet} 'connect to test net (default is main net)']" +
                    "[{-v <N> } 'set loglevel to N']" +
                    "[{-z <path> } 'set loglevel to N']" +
                    "[{-z <RAM> } 'use RAM instead of temp-files']" +
                    "[{-rpc-enable } 'enable JSON-RPC service']" +
                    "[{-rpc-port <port> } 'set HTTP JSON-RPC port (default is 7677)']" 
                , MAINNET_NAME, VERSION);
        }

        private static void shutdownHook() {
            Runtime.getRuntime().addShutdownHook(new Thread(() -> {
                log.info("Shutting down XDAG node, please hold tight...");
                try {
  
                	//shutdown服务
                } catch (Exception e) {
                    log.error("Exception occurred shutting down XDAG node: ", e);
                }
            }, "Shutdown Hook"));
        }
    }
}
